home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 1998 June / SGI Freeware 1998 June.iso / dist / fw_UMINNgopher.idb / usr / freeware / src / gopher_1.12 / gopherd / gopherd.c.z / gopherd.c
C/C++ Source or Header  |  1997-09-09  |  38KB  |  1,635 lines

  1. /********************************************************************
  2.  * $Author: drich $
  3.  * $Revision: 1.1 $
  4.  * $Date: 1995/10/03 04:08:31 $
  5.  * $Source: /proj/freeware1.0/gopher1.12/src/gopherd/RCS/gopherd.c,v $
  6.  * $State: Exp $
  7.  *
  8.  * Paul Lindner, University of Minnesota CIS.
  9.  *
  10.  * Copyright 1991, 1992 by the Regents of the University of Minnesota
  11.  * see the file "Copyright" in the distribution for conditions of use.
  12.  *********************************************************************
  13.  * MODULE: gopherd.c
  14.  * Routines to implement the gopher server.
  15.  *********************************************************************
  16.  * Revision History:
  17.  * $Log: gopherd.c,v $
  18.  * Revision 1.1  1995/10/03  04:08:31  drich
  19.  * gopher 1.2 check-in
  20.  *
  21.  * Revision 1.2.1.6  1993/01/09  02:37:29  lindner
  22.  * Added ftp gateway logging
  23.  * Changed gethostbyaddr() to work on UNICOS
  24.  *
  25.  * Revision 1.2.1.5  1993/01/05  21:32:25  lindner
  26.  * Fixed printfile() so that it deals with files with a period on a line
  27.  * all by itself correctly.  Also removed one writestring() call.
  28.  *
  29.  * Revision 1.2.1.4  1993/01/05  21:10:38  lindner
  30.  * Removed setuid() call that broke when using -u and chroot()
  31.  *
  32.  * Revision 1.2.1.3  1992/12/22  21:55:30  lindner
  33.  * fixed typo, int was meant to be double..  Grrrr
  34.  *
  35.  * Revision 1.2.1.2  1992/12/22  21:48:15  lindner
  36.  * Added extern maxload, fixes bug with previous version...
  37.  *
  38.  * Revision 1.2.1.1  1992/12/21  20:51:52  lindner
  39.  * Moved loadrestrict stuff to kernutils.c, also the server
  40.  * can now restrict for load average from standalone mode.
  41.  *
  42.  * Revision 1.2  1992/12/13  06:13:59  lindner
  43.  * Added code to do readline timeouts <mtm>
  44.  *
  45.  * Revision 1.1  1992/12/10  23:13:27  lindner
  46.  * gopher 1.1 release
  47.  *
  48.  *
  49.  *********************************************************************/
  50.  
  51.  
  52. /* Originally derived from an 
  53.  * Example of server using TCP protocol
  54.  * pp 284-5 Stevens UNIX Network Programming
  55.  */
  56.  
  57.  
  58. #include "gopherd.h"
  59. void LOGGopher();
  60.  
  61. static    int    uid = -2;
  62.  
  63. extern char *getdesc();
  64. extern double  maxload;
  65. void Process_Side();
  66.  
  67.  
  68.  
  69. /* This function is called on a read timeout from the network */
  70.  
  71. #include <setjmp.h>
  72. jmp_buf env;
  73.  
  74. SIGRETTYPE read_timeout()
  75. {
  76.      longjmp(env,1);
  77. }
  78.  
  79.  
  80. /*
  81.  * This routine finds out the hostname of the server machine.
  82.  * It uses a couple of methods to find the fully qualified 
  83.  * Domain name
  84.  */
  85.  
  86. char *
  87. GetDNSname(backupdomain)
  88.   char *backupdomain;
  89. {
  90.      static char DNSname[MAXHOSTNAMELEN];
  91.      struct hostent *hp;
  92.      char *cp;
  93.  
  94.      cp = GDCgetHostname(Config);
  95.      if (*cp != '\0')
  96.       return(cp);
  97.  
  98.      DNSname[0] = '\0';
  99.      /* Work out our fully-qualified name, for later use */
  100.      
  101.      if (gethostname(DNSname, MAXHOSTNAMELEN) != 0) {
  102.       fprintf(stderr, "Cannot determine the name of this host\n");
  103.       exit(-1);
  104.      }
  105.  
  106.      /* Now, use gethostbyname to (hopefully) do a nameserver lookup */
  107.      hp = gethostbyname( DNSname);
  108.  
  109.      /*
  110.       ** If we got something, and the name is longer than hostname, then
  111.       ** assume that it must the the fully-qualified hostname
  112.       */
  113.      if ( hp!=NULL && strlen(hp->h_name) > strlen(DNSname) ) 
  114.       strncpy( DNSname, hp->h_name, MAXHOSTNAMELEN );
  115.      else
  116.       strcat(DNSname, backupdomain);
  117.  
  118.      return(DNSname);
  119. }
  120.  
  121.  
  122. /*
  123.  * Tries to figure out what the currently connected port is.
  124.  * 
  125.  * If it's a socket then it will return the port of the socket, 
  126.  * if it isn't a socket then it returns -1.
  127.  */
  128.  
  129. int GetPort(fd)
  130.   int fd;
  131. {
  132.      struct sockaddr_in serv_addr;
  133.  
  134.      int length = sizeof(serv_addr);
  135.      
  136.      /** Try to figure out the port we're running on. **/
  137.      
  138.      if (getsockname(fd, (struct sockaddr *) &serv_addr,&length) == 0)
  139.       return(ntohs(serv_addr.sin_port));
  140.      else
  141.       return(-1);
  142.  
  143. }
  144.  
  145.  
  146. /*
  147.  * This function returns a socket file descriptor bound to the given port
  148.  */
  149.  
  150. int
  151. bind_to_port(port) 
  152.   int port;
  153. {
  154.     struct sockaddr_in serv_addr;
  155.     struct linger linger;
  156.     int reuseaddr = 1;
  157.     int sockfd;
  158.  
  159.      
  160.      if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  161.       err_dump("server: can't open stream socket");
  162.      
  163.      /** Bind our local address so that the client can send to us **/
  164.      
  165.      bzero((char *) &serv_addr, sizeof(serv_addr));
  166.      serv_addr.sin_family         = AF_INET;
  167.      serv_addr.sin_addr.s_addr     = htonl(INADDR_ANY);
  168.      serv_addr.sin_port        = htons(port);
  169.      
  170.      if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) <0)
  171.       err_dump("server: can't bind local address");
  172.      linger.l_onoff = linger.l_linger = 0;
  173.      if (setsockopt(sockfd, SOL_SOCKET, SO_LINGER, (char *)&linger,
  174.             sizeof (linger)) < 0)
  175.       err_dump("server: can't turn off linger sockopt");
  176.  
  177.      if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuseaddr,
  178.             sizeof(reuseaddr)) < 0)
  179.       err_dump("server: can't set REUSEADDR!");
  180.  
  181.     return(sockfd);
  182. }
  183.  
  184. void
  185. main(argc, argv)
  186.   int     argc;
  187.   char     *argv[];
  188. {
  189.      int                childpid;
  190.      int                sockfd, newsockfd;
  191.      int                clilen;
  192.      struct sockaddr_in cli_addr;
  193.      boolean            OptionsRead = FALSE;
  194.  
  195.  
  196.      /*** for getopt processing ***/
  197.      int c;
  198.      extern char *optarg;
  199.      extern int optind;
  200.      int errflag =0;
  201.  
  202.  
  203.      pname = argv[0];
  204.      strcpy(Data_Dir, DATA_DIRECTORY);
  205.      err_init();    /* openlog() early - before we chroot() of course */
  206.  
  207.      /*** Check argv[0], see if we're running as gopherls, etc. ***/
  208.  
  209.      RunServer = RunLS = RunIndex = FALSE;
  210.  
  211.      if (strstr(argv[0], "gopherls") != NULL) {
  212.       RunLS = TRUE;
  213.      } else if (strstr(argv[0], "gindexd") != NULL) {
  214.       RunIndex = TRUE;
  215.       dochroot = FALSE;
  216.      } else 
  217.       RunServer = TRUE;  /** Run the server by default **/
  218.  
  219.      Config = GDCnew();  /** Set up the general configuration **/
  220.  
  221.      while ((c = getopt(argc, argv, "mCDIcL:l:o:u:U:")) != -1)
  222.       switch (c) {
  223.       case 'D':
  224.            DEBUG = TRUE;
  225.            break;
  226.  
  227.       case 'I':
  228.            RunFromInetd = TRUE;
  229.            break;
  230.  
  231.       case 'C':
  232.            Caching = FALSE;
  233.            break;
  234.  
  235.       case 'm':
  236.         if (RunIndex)
  237.             MacIndex = TRUE;
  238.         break;
  239.  
  240.       case 'c':
  241.            dochroot = FALSE;
  242.            if (!RunFromInetd) {
  243.             printf("Not using chroot() - be careful\n");
  244.             if ( getuid() == 0 || geteuid() == 0 )
  245.              printf("You should run without root perms\n");
  246.            }
  247.            break;
  248.  
  249.       case 'L':  /** Load average at which to restrict usage **/
  250.            maxload = atof(optarg);
  251.            break;
  252.  
  253.       case 'l':  /** logfile name **/
  254.            if (*optarg == '/')
  255.             GDCsetLogfile(Config, optarg);
  256.            else {
  257.             char tmpstr[256];
  258.             
  259.             getwd(tmpstr);
  260.             strcat(tmpstr, "/");
  261.             strcat(tmpstr, optarg);
  262.             
  263.             GDCsetLogfile(Config, tmpstr);
  264.            }
  265.            break;
  266.            
  267.       case 'o': /** option file **/
  268.            if (*optarg == '/')
  269.             GDCfromFile(Config, optarg);
  270.            else {
  271.             char tmpstr[256];
  272.             getwd(tmpstr);
  273.             strcat(tmpstr, "/");
  274.             strcat(tmpstr, optarg);
  275.             GDCfromFile(Config, tmpstr);
  276.            }
  277.            OptionsRead = TRUE;
  278.            break;
  279.  
  280.       case 'u':
  281.            {
  282.             struct passwd *pw = getpwnam( optarg );
  283.             if ( !pw ) {
  284.              fprintf(stderr,
  285.                   "Could not find user '%s' in passwd file\n",
  286.                   optarg);
  287.              errflag++;
  288.             } else {
  289.              uid = pw->pw_uid;
  290.              if (!RunFromInetd) {
  291.                   printf("Running as user '%s' (%d)\n",
  292.                    optarg, uid);
  293.              }
  294.             }
  295.            }
  296.            break;
  297.  
  298.       case 'U':    /* set uid to use */
  299.            uid = atoi( optarg );
  300.            if (!RunFromInetd) {
  301.             printf("Running using uid %d\n", uid);
  302.            }
  303.            break;
  304.       case '?':
  305.       case 'h':
  306.            errflag++;
  307.            break;
  308.       }
  309.  
  310.  
  311.      if (errflag) {
  312.       fprintf(stderr, "Usage: %s [-CDIc] [-u userid] [-U uid] [-s securityfile] [-l logfile] <datadirectory> <port>\n", argv[0]);
  313.       fprintf(stderr, "   -C  turns caching off\n");
  314.       fprintf(stderr, "   -D  enables copious debugging info\n");
  315.       fprintf(stderr, "   -I  enable \"inetd\" mode\n");
  316.       fprintf(stderr, "   -c  disable chroot(), use secure open routines instead\n");
  317.       fprintf(stderr, "   -u  specifies the username for use with -c\n");
  318.       fprintf(stderr, "   -U  specifies the UID for use with -c\n");
  319.       fprintf(stderr, "   -o  override the default options file '%s'\n", CONF_FILE);
  320.       fprintf(stderr, "   -l  specifies the name of a logfile\n");
  321.           
  322.       exit(-1);
  323.      }
  324.  
  325.      if (uid == -2) 
  326.       uid = getuid();  /** Run as current user... **/
  327.  
  328.      if ( uid == 0 && !RunFromInetd )
  329.       printf("Warning! You really shouldn't run the server as root!...\n");
  330.  
  331.  
  332.      if (optind < argc) {
  333.       strcpy(Data_Dir, argv[optind]);
  334.       optind++;
  335.      } else if (RunLS)
  336.       strcpy(Data_Dir, "/");
  337.  
  338.      if (optind < argc) {
  339.       GopherPort = atoi(argv[optind]);
  340.       optind++;
  341.      }
  342.  
  343.      /** Read the options in, if not overridden **/
  344.      if (OptionsRead == FALSE)
  345.       GDCfromFile(Config, CONF_FILE);
  346.      
  347.  
  348.      if (RunLS) {
  349.       Zehostname =GetDNSname(DOMAIN_NAME);
  350.       Caching = FALSE;
  351.  
  352.       fflush(stdout);
  353.       uchdir(Data_Dir);
  354.  
  355.       listdir(fileno(stdout), "/");
  356.       exit(0);
  357.      }
  358.  
  359.      if (!RunFromInetd) {
  360.       printf("Gopher Server, Copyright 1991,92 the Regents of the University of Minnesota\n");
  361.       printf("See the file 'Copyright' for conditions of use\n");
  362.       printf("Data directory is %s\n", Data_Dir);
  363.       printf("Port is %d\n", GopherPort);
  364.      }
  365.  
  366.      if (*GDCgetLogfile(Config) != '\0' && !RunFromInetd)
  367.       printf("Logging to File %s\n", GDCgetLogfile(Config));
  368.  
  369.      /*
  370.       * Would like to setuid() here, but have to wait until after the
  371.       * bind() in case we're going to be running on a privileged port.
  372.       */
  373.  
  374.      if (uchdir(Data_Dir)) {
  375.       if (!RunIndex) {
  376.            fprintf(stderr, "Cannot change to data directory!! %s \n",Data_Dir);
  377.            exit(-1);
  378.       }
  379.      }
  380.  
  381.      if (dochroot && getuid() != 0) {
  382.       fprintf(stderr, "Gopherd uses the privileged call chroot().  Please become root.\n");
  383.       exit(-1);
  384.      }
  385.  
  386.      fflush(stderr);
  387.      fflush(stdout);
  388.  
  389.      if (DEBUG == FALSE && RunFromInetd==FALSE)
  390.       daemon_start(0);
  391.  
  392.  
  393.      /*** Hmmm, does this look familiar? :-) ***/
  394.  
  395.  
  396.      err_init();    /* does this look familiar too?? :-) */
  397.  
  398.      /** Ask the system what host we're running on **/
  399.  
  400.      Zehostname = GetDNSname(DOMAIN_NAME);
  401.  
  402.  
  403.      if (RunFromInetd) {
  404.       /** Ask the system which port we're running on **/
  405.       int newport=0;
  406.       if ((newport =GetPort(0)) !=0)
  407.            GopherPort=newport;
  408.  
  409.       /*** Do the stuff for inetd ***/
  410.  
  411.       while(do_command(0)!=0);    /* process the request */
  412.       exit(0);
  413.      }
  414.  
  415.      /** Open a TCP socket (an internet stream socket **/
  416.      sockfd = bind_to_port(GopherPort);
  417.  
  418.      /* have to setuid() here, in case we're using a privileged port */
  419. /*     if ( setuid(uid) != 0 )
  420.       err_sys("Cannot setuid(%d): ",uid);*/
  421.  
  422.      listen(sockfd, 5);
  423.      
  424.      for ( ; ; ) {
  425.       /*
  426.        * Wait for a connection from a client process.
  427.        * This is an example of a concurrent server.
  428.        */
  429.       
  430.       clilen = sizeof(cli_addr);
  431.       newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr,
  432.                  &clilen);
  433.  
  434.       if (newsockfd < 0)
  435.            err_dump("server: accept error");
  436.       
  437.       if ( (childpid = fork()) < 0)
  438.            err_dump("server: fork error");
  439.       
  440.       else if (childpid == 0) {    /* Child process */
  441.            close(sockfd);        /* close original socket */
  442.  
  443.            while(do_command(newsockfd)!=0);    /* process the request */
  444.            exit(0);
  445.       }
  446.       /** clean up any zombie children **/
  447.       sig_child();
  448.  
  449.       close(newsockfd);         /* parent process */
  450.      }
  451. }
  452.  
  453.  
  454. /*
  455.  *
  456.  *  Code stolen from nntp.....
  457.  *
  458.  * inet_netnames -- return the network, subnet, and host names of
  459.  * our peer process for the Internet domain.
  460.  *
  461.  *      Parameters:     "sock" is our socket
  462.  *                      "host_name"
  463.  *                      is filled in by this routine with the
  464.  *                      corresponding ASCII names of our peer.
  465.  *       
  466.  *                      if there doesn't exist a hostname in DNS etal,
  467.  *                      the IP# will be inserted for the host_name
  468.  *
  469.  *                      "ipnum" is filled in with the ascii IP#
  470.  *      Returns:        Nothing.
  471.  *      Side effects:   None.
  472.  */
  473.  
  474. void
  475. inet_netnames(sockfd, host_name, ipnum)
  476.   int  sockfd;
  477.   char *host_name;
  478.   char *ipnum;
  479. {
  480.      struct sockaddr_in      sa;
  481.      int                     length;
  482.      u_long                  net_addr;
  483.      struct hostent          *hp;
  484.  
  485.      length = sizeof(sa);
  486.      getpeername(sockfd, &sa, &length);
  487.      strcpy(ipnum, inet_ntoa(sa.sin_addr));
  488.      strcpy(host_name, inet_ntoa(sa.sin_addr));
  489.  
  490.      hp = gethostbyaddr((char *) &sa.sin_addr,
  491.             sizeof (sa.sin_addr.s_addr), AF_INET);
  492.      
  493.      if (hp != NULL)
  494.       (void) strcpy(host_name, hp->h_name);
  495.  
  496. }
  497.  
  498.  
  499.  
  500. /*
  501.  * This finds the current peer and the time and  jams it into the
  502.  * logfile (if any) and adds the message at the end
  503.  */
  504.  
  505. void
  506. LOGGopher(sockfd, message)
  507.   int sockfd;
  508.   char *message;
  509. {
  510.      static char     host_name[256];
  511.      static char     ipnum[256];
  512.      time_t          Now;
  513.      char            *cp;
  514.                      /* cp + ' ' + host_name + ' : ' + MAXLINE + '\n' + '\0' */
  515.      char            buf[286+MAXLINE];
  516.      struct flock    lock;
  517.    
  518.  
  519.      host_name[0] = '\0';
  520.  
  521.      if (LOGFileDesc != -1) {
  522.       
  523.       if (sockfd > -1) {
  524.            inet_netnames(sockfd,host_name, ipnum);
  525.       }
  526.  
  527.       lock.l_type = F_WRLCK;
  528.       lock.l_whence = SEEK_SET;
  529.           lock.l_start = 0L;
  530.           lock.l_len = 0L;
  531.           fcntl(LOGFileDesc, F_SETLKW, &lock);
  532.  
  533.       time(&Now);         /* Include this in the lock to make sure */
  534.       cp = ctime(&Now);   /*  log entries are chronological */
  535.       ZapCRLF(cp);
  536.  
  537.           /* someone else may have written to the file since we opened it */
  538.           lseek(LOGFileDesc, 0L, SEEK_END);
  539.   
  540.           sprintf(buf, "%s %d %s : %s\n", cp, getpid(), host_name, message);
  541.           write(LOGFileDesc, buf, strlen(buf));
  542.           
  543.           /* unlock the file */
  544.           lock.l_type = F_UNLCK;
  545.           fcntl(LOGFileDesc, F_SETLKW, &lock);
  546.       
  547.       if (DEBUG)
  548.            printf("%s %d %s : %s\n", cp, getpid(), host_name, message);
  549.       
  550.      }
  551. }
  552.  
  553. void
  554. process_mailfile(sockfd, Mailfname)
  555.   int sockfd;
  556.   char *Mailfname;
  557. {
  558.      FILE *Mailfile;
  559.      char Zeline[MAXLINE];
  560.      char outputline[MAXLINE];
  561.      char Title[MAXLINE];
  562.      long Startbyte=0, Endbyte=0, Bytecount=0;
  563.      boolean flagged = 0;
  564.  
  565.      Mailfile = rfopen(Mailfname, "r");
  566.  
  567.      if (Mailfile == NULL) {
  568.       Abortoutput(sockfd, "Cannot access file");
  569.       return;
  570.      }
  571.  
  572.      while (fgets(Zeline, MAXLINE, Mailfile) != NULL) {
  573.       if (strncmp(Zeline, "Subject: ", 9)==0 && (!flagged)) {
  574.            flagged =1;
  575.            strcpy(Title, Zeline + 9);
  576.            ZapCRLF(Title);
  577.            if (DEBUG)
  578.             fprintf(stderr, "Found title %s", Title);
  579.       }
  580.       
  581.       if (is_mail_from_line(Zeline)==0) {
  582.            Endbyte = Bytecount;
  583.            flagged =0;
  584.  
  585.            if (Endbyte != 0) {
  586.             sprintf(outputline, "0%s\tR%d-%d-%s\t%s\t%d\r\n", 
  587.                 Title, Startbyte, Bytecount, Mailfname,
  588.                 Zehostname, GopherPort);
  589.             if (writestring(sockfd, outputline) < 0)
  590.              LOGGopher(sockfd, "Client went away"), exit(-1);
  591.             Startbyte=Bytecount;
  592.             *Title = '\0';
  593.            }
  594.       }
  595.  
  596.       Bytecount += strlen(Zeline);
  597.      }
  598.  
  599.      if (*Title != '\0') {
  600.       sprintf(outputline, "0%s\tR%d-%d-%s\t%s\t%d\r\n", 
  601.           Title, Startbyte, Bytecount, Mailfname, 
  602.           Zehostname, GopherPort);
  603.       if (writestring(sockfd, outputline)<0)
  604.            LOGGopher(sockfd, "Client went away"),exit(-1);
  605.      }      
  606.  
  607.  
  608.      if (writestring(sockfd, ".\r\n")<0)
  609.       LOGGopher(sockfd, "Client went away"),exit(-1);
  610. }
  611.  
  612.  
  613.  
  614. boolean
  615. Can_Read(sockfd)
  616.   int sockfd;
  617. {
  618.      int                length;
  619.      char               host_name[256];
  620.      char               ip[256];
  621.      char               *cp;
  622.  
  623.      inet_netnames(sockfd, host_name, ip);
  624.  
  625.      return(GDCCanRead(Config, host_name, ip));
  626. }
  627.  
  628. boolean
  629. Can_Browse(sockfd)
  630.   int sockfd;
  631. {
  632.      int                length;
  633.      char               host_name[256];
  634.      char               ip[256];
  635.      char               *cp;
  636.  
  637.      inet_netnames(sockfd, host_name, ip);
  638.  
  639.      return(GDCCanBrowse(Config, host_name, ip));
  640. }
  641.  
  642. boolean
  643. Can_Search(sockfd)
  644.   int sockfd;
  645. {
  646.      int                length;
  647.      char               host_name[256];
  648.      char               ip[256];
  649.      char               *cp;
  650.  
  651.      inet_netnames(sockfd, host_name, ip);
  652.  
  653.      return(GDCCanSearch(Config, host_name, ip));
  654. }
  655.  
  656.  
  657. int
  658. do_command(sockfd)
  659.   int sockfd;
  660. {
  661.      char inputline[MAXLINE];
  662.      int length;        /* Length of the command line */
  663.      char logline[MAXLINE];
  664.      char *selstr;
  665.  
  666.      /*** Reopen the log file ***/
  667.  
  668.      if (*GDCgetLogfile(Config) != '\0') {
  669.       LOGFileDesc = uopen(GDCgetLogfile(Config), O_WRONLY | O_APPEND |O_CREAT, 0644);
  670.       
  671.       if (LOGFileDesc == -1) {
  672.            printf("Can't open the logfile: %s\n", GDCgetLogfile(Config));
  673.            exit(-1);
  674.       }
  675.      }
  676.  
  677.      if(LoadTooHigh()) {
  678.       LOGGopher(sockfd, "System Load Too High.");
  679.       Abortoutput(sockfd, "System is too busy right now. Please try again later.");
  680.       exit(-1);
  681.      }
  682.  
  683.      /*** Make sure we do a tzset before doing a chroot() ***/
  684.      tzset();
  685.  
  686.      /** Change our root directory **/
  687.      
  688.      if ( dochroot ) {
  689.       if (chroot(Data_Dir)) {
  690.            Abortoutput(sockfd, "Data_Dir dissappeared!");
  691.            exit(-1);
  692.       }
  693.       uchdir("/");    /* needed after chroot */
  694.      }
  695.  
  696.      if (setuid(uid)) {
  697.       LOGGopher(sockfd, "Can't set UID!");
  698.       Abortoutput(sockfd, "Can't set UID!");
  699.       exit(-1);
  700.      }
  701.       
  702.  
  703.      (void) signal(SIGALRM,read_timeout);
  704.      (void) alarm(READTIMEOUT);
  705.  
  706.      if(setjmp(env)) {
  707.       LOGGopher(sockfd,"readline: Timed out!");
  708.       Abortoutput(sockfd,"readline: Timed out!");
  709.       exit(-1);
  710.      }
  711.  
  712.      length = readline(sockfd, inputline, MAXLINE); /** Get the line **/
  713.  
  714.      /** Disable the alarm signal **/
  715.      (void) alarm(0);
  716.      (void) signal(SIGALRM,SIG_IGN);
  717.  
  718.  
  719.      if (length <= 0) {
  720.       close(sockfd);
  721.       err_quit("getcommand: readline error");
  722.      }
  723.      
  724.      ZapCRLF(inputline);
  725.  
  726.  
  727.      /*
  728.       * Decide if we're an HTML server or not...
  729.       */
  730.  
  731.      if (strncmp(inputline, "GET /", 5) == 0) {
  732.  
  733.       UsingHTML = TRUE;
  734.       selstr = inputline+5;
  735.  
  736.       /** Convert the hex things back to text... ***/
  737.       Fromhexstr(selstr, selstr);
  738.  
  739.      } else
  740.       selstr = inputline;
  741.  
  742.      if (RunIndex) {
  743.       /*** Run like the old gindexd thing. ***/
  744.       
  745.       char tempstr[512];
  746.       
  747.       uchdir("/");
  748.  
  749.       strcpy(tempstr, Data_Dir);
  750.       strcat(tempstr, "\t");
  751.       if (*selstr == '\t')
  752.            strcat(tempstr, selstr+1);
  753.       else
  754.            strcat(tempstr, selstr);
  755.  
  756.       strcpy(Data_Dir, "/");
  757.       
  758.       if (DEBUG)
  759.            writestring(sockfd, tempstr);
  760.  
  761.  
  762.       Do_IndexTrans(sockfd, tempstr);
  763.       return(0);
  764.      }
  765.  
  766.      /*** With the funky new capability system we can just check the
  767.           first letter, end decide what the object refers to. ***/
  768.  
  769.      switch (*selstr) {
  770.      case '\0':
  771.      case '\t':
  772.  
  773.       /*** The null capability, so it's not a file, probably wants
  774.            to talk to a directory server ***/
  775.  
  776.       /*** we'll just do a "list" of the root directory, with no user
  777.            capability.  ***/
  778.  
  779.       listdir(sockfd, "/");
  780.       LOGGopher(sockfd, "Root Connection");
  781.       break;
  782.  
  783.      case 'h':
  784.       /*** A raw html file ***/
  785.       /*** Turn off html'ing and just dump the file ***/
  786.       UsingHTML = FALSE;
  787.  
  788.      case '0':
  789.       /*** It's a generic file capability ***/
  790.       printfile(sockfd, selstr+1, 0, -1);
  791.  
  792.       /*** Log it ***/
  793.       strcpy(logline, "retrieved file ");
  794.       strcat(logline, selstr+1);
  795.       LOGGopher(sockfd, logline);
  796.       break;
  797.  
  798.      case '1':
  799.       /*** It's a directory capability ***/
  800.       listdir(sockfd, selstr+1);
  801.  
  802.       /** Log it **/
  803.       strcpy(logline, "retrieved directory ");
  804.       strcat(logline, selstr+1);
  805.       LOGGopher(sockfd, logline);
  806.  
  807.       break;
  808.  
  809.      case '7':
  810.       /*** It's an index capability ***/
  811.       if (Can_Search(sockfd) == FALSE) {
  812.            char tmpstr[256];
  813.  
  814.            Abortoutput(sockfd, GDCgetBummerMsg(Config));
  815.             
  816.            sprintf(tmpstr, "Denied access for %s", selstr+1);
  817.            LOGGopher(sockfd, tmpstr);
  818.            break;
  819.       }
  820.  
  821.       Do_IndexTrans(sockfd, selstr+1);
  822.  
  823.       break;
  824.  
  825.      case 'I':
  826.      case '9':
  827.       /*** It's a binary thingie... ***/
  828.       /*** Okay, it's not a sound, but what the heck.... ***/
  829.       echosound(sockfd, selstr+1);
  830.       
  831.       /* Log it */
  832.       strcpy(logline, "retrieved binary ");
  833.       strcat(logline, selstr+1);
  834.       LOGGopher(sockfd, logline);
  835.       break;
  836.  
  837.      case 's':
  838.       /*** It's a sound capability ***/
  839.       echosound(sockfd, selstr+1);
  840.  
  841.       /* Log it */
  842.       strcpy(logline, "retrieved sound ");
  843.       strcat(logline, selstr+1);
  844.       LOGGopher(sockfd, logline);
  845.       break;
  846.  
  847.      case 'm':
  848.       /*** This is an internal identifier ***/
  849.       /*** The m paired with an Objtype of 1 makes a mail spool file
  850.            into a directory.
  851.       ***/
  852.       if (Can_Browse(sockfd) == FALSE) {
  853.            char tmpstr[256];
  854.            Abortoutput(sockfd,  GDCgetBummerMsg(Config));
  855.            sprintf(tmpstr, "Denied access for %s", selstr+1);
  856.            LOGGopher(sockfd, tmpstr);
  857.            break;
  858.       }
  859.  
  860.       process_mailfile(sockfd, selstr + 1);
  861.  
  862.       /** Log it **/
  863.       strcpy(logline, "retrieved maildir ");
  864.       strcat(logline, selstr+1);
  865.       LOGGopher(sockfd, logline);
  866.  
  867.       break;
  868.  
  869.      case 'R':
  870.       /*** This is an internal identifier ***/
  871.       /*** The R defines a range  ****/
  872.       /*** The format is R<startbyte>-<endbyte>-<filename> **/
  873.      {
  874.       int startbyte, endbyte;
  875.       char *cp, *oldcp;
  876.  
  877.       cp = strchr(selstr+1, '-');
  878.       
  879.       if (cp == NULL) {
  880.            Abortoutput(sockfd, "Range specifier error");
  881.            break;
  882.       }
  883.       
  884.       *cp = '\0';
  885.       startbyte = atoi(selstr+1);
  886.       oldcp = cp+1;
  887.  
  888.       cp = strchr(oldcp, '-');
  889.       
  890.       if (cp == NULL) {
  891.            Abortoutput(sockfd, "Range specifier error");
  892.            exit(-1);
  893.       }
  894.  
  895.       *cp = '\0';
  896.       endbyte = atoi(oldcp);
  897.       oldcp = cp + 1;
  898.       if (DEBUG)
  899.            fprintf(stderr, "Start: %d, End: %d  File: %s\n", startbyte, endbyte, oldcp);
  900.  
  901.       writestring(sockfd, "This section is from the document '");
  902.       writestring(sockfd, oldcp);
  903.       writestring(sockfd, "'.\r\n\r\n");
  904.       printfile(sockfd, oldcp, startbyte, endbyte);
  905.  
  906.       /*** Log it ***/
  907.       sprintf(logline, "retrieved range %d - %d of file %s", startbyte, endbyte, oldcp);
  908.       LOGGopher(sockfd, logline);
  909.       break;
  910.      }
  911.  
  912.      case 'f':
  913.       if (Can_Browse(sockfd) == FALSE) {
  914.            char tmpstr[256];
  915.            Abortoutput(sockfd,  GDCgetBummerMsg(Config));
  916.            sprintf(tmpstr, "Denied access for %s", selstr);
  917.            LOGGopher(sockfd, tmpstr);
  918.            break;
  919.       }
  920.  
  921.       if (strncmp(selstr, "ftp:",4)==0){
  922.            sprintf(logline, "retrieved %s", selstr);
  923.            LOGGopher(sockfd, logline);
  924.  
  925.            SendFtpQuery(sockfd, selstr+4);
  926.            TranslateResults(sockfd);
  927.            break;
  928.       }
  929.       break;
  930.  
  931.      case 'e':
  932.       if (Can_Browse(sockfd) == FALSE) {
  933.            char tmpstr[256];
  934.            Abortoutput(sockfd,  GDCgetBummerMsg(Config));
  935.            sprintf(tmpstr, "Denied access for %s", selstr);
  936.            LOGGopher(sockfd, tmpstr);
  937.            break;
  938.       }
  939.  
  940.       if (strncmp(selstr, "exec:", 5)==0) {
  941.            /* args are between colons */
  942.            char *args, *command;
  943.            
  944.            command = strrchr(selstr + 5, ':');
  945.            if (command == NULL)
  946.             break;
  947.  
  948.            if (*(selstr+5) == ':' && *(selstr+6) == ':')
  949.             args = NULL;
  950.            else
  951.             args = selstr+5;
  952.  
  953.            *command = '\0';
  954.            command++;
  955.            
  956.            EXECargs = args;
  957.  
  958.            printfile(sockfd, command, 0, -1);
  959.       }
  960.       break;
  961.  
  962.      case 'w':
  963.      {
  964.       if (strncmp(selstr, "waissrc:", 8) == 0) {
  965.            if (Can_Search(sockfd) == FALSE) {
  966.             char tmpstr[256];
  967.             Abortoutput(sockfd,  GDCgetBummerMsg(Config));
  968.             sprintf(tmpstr, "Denied access for %s", selstr);
  969.             LOGGopher(sockfd, tmpstr);
  970.             break;
  971.            }
  972.  
  973.            SearchRemoteWAIS(sockfd, selstr+8);
  974.            break;
  975.       }
  976.       else if (strncmp(selstr, "waisdocid:", 10) == 0) {
  977.            if (Can_Browse(sockfd) == FALSE) {
  978.             char tmpstr[256];
  979.             Abortoutput(sockfd,  GDCgetBummerMsg(Config));
  980.             sprintf(tmpstr, "Denied access for %s", selstr);
  981.             LOGGopher(sockfd, tmpstr);
  982.             break;
  983.            }
  984.            Fetchdocid(sockfd, selstr+10);
  985.            break;
  986.       }
  987.      }
  988.  
  989.  
  990.      default:
  991.       /*** Hmmm, must be an old link... Let's see if it exists ***/
  992.  
  993.       switch (isadir(selstr)) {
  994.       case -1:
  995.            /* no such file */
  996.            sprintf(logline, "'%s' does not exist", selstr);
  997.            LOGGopher(sockfd, logline);
  998.            Abortoutput(sockfd, logline);
  999.            break;
  1000.  
  1001.       case 0:
  1002.            /* it's a file */
  1003.            printfile(sockfd, selstr, 0, -1);
  1004.            
  1005.            /* Log it... */
  1006.            strcpy(logline, "retrieved file ");
  1007.            strcat(logline, selstr);
  1008.            LOGGopher(sockfd, logline);
  1009.  
  1010.            break;
  1011.  
  1012.       case 1:
  1013.            /* it's a directory */
  1014.            listdir(sockfd, selstr);
  1015.  
  1016.            /* Log it */
  1017.            strcpy(logline, "retrieved directory ");
  1018.            strcat(logline, inputline);
  1019.            LOGGopher(sockfd, logline);
  1020.  
  1021.            break;
  1022.       }
  1023.      }
  1024.  
  1025.      return(0);
  1026. }
  1027.  
  1028. /*
  1029.  * Cache timeout value.
  1030.  *   If cache is less than secs seconds old, it's ok.
  1031.  *   Otherwise, compare time of cache to dir and all files in dir and dir/.cap.
  1032.  *   If cache is newest, it's ok, otherwise it must be rebuilt.
  1033.  * 
  1034.  * Not really great for big directories, but better in general for smaller
  1035.  * directories..
  1036.  */
  1037.  
  1038. boolean
  1039. Cachetimedout(cache, secs, dir)
  1040.   char *cache;
  1041.   int secs;
  1042.   char *dir;
  1043. {
  1044.      STATSTR       buf;
  1045.      int           result;
  1046.      time_t        now;
  1047.  
  1048.      result = rstat(cache, &buf);
  1049.  
  1050.      if (result != 0)
  1051.       return(-1);
  1052.  
  1053.      time(&now);
  1054.      
  1055.      if (DEBUG) 
  1056.       printf("Cache now: %d, cache file: %d", now,buf.st_mtime);
  1057.      
  1058.      if ( now < (buf.st_mtime + secs))
  1059.       return(FALSE);
  1060.      else
  1061.       return(TRUE);
  1062.  
  1063. }
  1064.  
  1065. /*
  1066.  * Returns true (1) for a directory
  1067.  *         false (0) for a file
  1068.  *         -1 for anything else
  1069.  */
  1070.  
  1071. boolean
  1072. isadir(path)
  1073.   char *path;
  1074. {
  1075.      STATSTR buf;
  1076.      int result;
  1077.  
  1078.      result = rstat(path, &buf);
  1079.  
  1080.      if (result != 0)
  1081.       return(-1);
  1082.      
  1083.      if (S_ISDIR(buf.st_mode)) {
  1084.       if (! access(path, F_OK))
  1085.            return(1);
  1086.       else
  1087.            return(-1);
  1088.      }
  1089.      else if (S_ISREG(buf.st_mode))
  1090.       return(0);
  1091.      else
  1092.       return(-1);
  1093. }
  1094.  
  1095.  
  1096. /*
  1097.  * This function tries to find out what type of file a pathname is.
  1098.  * It then fills in the VAR type variables ObjType & ServerPath with
  1099.  * corresponding info.
  1100.  */
  1101. void
  1102. Getfiletypes(newpath, filename, ObjType, ServerPath)
  1103.   char *newpath;
  1104.   char *filename;
  1105.   char *ObjType;
  1106.   char **ServerPath;
  1107. {
  1108.      boolean dirresult;
  1109.      int Zefilefd;
  1110.      static char Zebuf[256];
  1111.      char *cp;
  1112.      static char Selstr[512];
  1113.  
  1114.      
  1115.      if (ServerPath != NULL)         /* Don't overwrite existing path if any */
  1116.       *ServerPath = Selstr; 
  1117.  
  1118.  
  1119.      dirresult = isadir(filename);
  1120.  
  1121.      if (dirresult == -1) {             /** Symlink or Special **/
  1122.       *ObjType = '3';
  1123.       return;
  1124.      }
  1125.  
  1126.      if (dirresult == 1) {
  1127.       *ObjType = '1';
  1128.       *Selstr = '1';
  1129.       strcpy(Selstr +1, newpath);
  1130.       return;
  1131.      }
  1132.          
  1133.      
  1134.      else {          /** Some kind of data file.... */
  1135.  
  1136.       /*** The default is a generic text file ***/
  1137.  
  1138.       *ObjType = '0';
  1139.       *Selstr = '0';
  1140.       strcpy(Selstr + 1, newpath);
  1141.  
  1142.       /*** Test and see if the thing exists... and is readable ***/
  1143.       
  1144.       if ((Zefilefd = ropen(filename, O_RDONLY)) < 0) {
  1145.            *ObjType = '3';
  1146.            return;
  1147.       }
  1148.       
  1149.       bzero(Zebuf, sizeof(Zebuf));
  1150.       read(Zefilefd, Zebuf, sizeof(Zebuf));
  1151.       close(Zefilefd);
  1152.       
  1153.       /*** Check the first few bytes for sound data ***/
  1154.       
  1155.       cp = Zebuf;
  1156.  
  1157.       if (strncmp(cp, ".snd", 4)==0) {
  1158.            *ObjType = 's';
  1159.            *Selstr = 's';
  1160.            strcpy(Selstr+1, newpath);
  1161.       }
  1162.  
  1163.       /*** Check and see if it's mailbox data ***/
  1164.       
  1165.       if (is_mail_from_line(Zebuf)==0) {
  1166.            *ObjType = '1';
  1167.            *Selstr = 'm';
  1168.            strcpy(Selstr+1, newpath);
  1169.       }
  1170.       
  1171.  
  1172.       /*** Check for uuencoding data ***/
  1173.  
  1174.       if (strncmp(cp,"begin",6) == 0)  {
  1175.            *ObjType = '6';
  1176.            *Selstr = '6';
  1177.            strcpy(Selstr+1, newpath);
  1178.       }
  1179.       
  1180.       /*** Check for GIF magic code ***/
  1181.       
  1182.       if (strncmp(cp, "GIF", 3) == 0) {
  1183.            *ObjType = 'I';
  1184.             *Selstr = 'I';
  1185.             strcpy(Selstr + 1, newpath);
  1186.        }
  1187.  
  1188.       /*** Okay, now let's check for the stuff from gopherd.conf files ***/
  1189.      {
  1190.       char Gtype, *prefix;
  1191.  
  1192.            if (GDCExtension(Config, filename, &Gtype, &prefix)) {
  1193.            *ObjType = Gtype;
  1194.            strcpy(Selstr, prefix);
  1195.            strcpy(Selstr+strlen(prefix), newpath);
  1196.       }
  1197.      }
  1198.                
  1199.  
  1200.      }
  1201.  
  1202. }
  1203.  
  1204.  
  1205.  
  1206.  
  1207. /*
  1208. ** This function lists out what is in a particular directory.
  1209. ** it also outputs the contents of link files.
  1210. **
  1211. ** It also checks for the existance of a .cache file if caching is
  1212. ** turned on...
  1213. **
  1214. ** Ack is this ugly.
  1215. */
  1216.  
  1217. void
  1218. listdir(sockfd, pathname)
  1219.   int sockfd;
  1220.   char *pathname;
  1221. {
  1222.      DIR                   *ZeDir;
  1223.      char                  sidename[256];
  1224.      char                  filename[256];
  1225.      static char           newpath[512];
  1226. #ifdef DL
  1227.      char                  dlpath[2];    /*** for DL**/
  1228.      char                  *dlout;
  1229. #endif
  1230.      FILE                  *SideFile;
  1231.      static GopherStruct   *Gopherp = NULL;
  1232.      char               Typep, *Pathp, *cachefile;
  1233.      struct dirent         *dp;
  1234.  
  1235.  
  1236.      /*** Make our gopherobj ****/
  1237.      if (Gopherp == NULL)
  1238.       Gopherp = GSnew();
  1239.  
  1240.      if (rchdir(pathname)<0) {
  1241.       Abortoutput(sockfd, "- Cannot access that directory");
  1242.           return;
  1243.      }
  1244.      
  1245.      if (UsingHTML)
  1246.       cachefile = ".cache.html";
  1247.      else
  1248.       cachefile = ".cache";
  1249.  
  1250.      if (Can_Browse(sockfd) == FALSE) {
  1251.       char tmpstr[256];
  1252.       Abortoutput(sockfd,  GDCgetBummerMsg(Config));
  1253.       sprintf(tmpstr, "Denied access for %s", pathname);
  1254.       LOGGopher(sockfd, tmpstr);
  1255.       return;
  1256.      }
  1257.  
  1258.  
  1259.      if (Caching && Cachetimedout(cachefile, CACHE_TIME, ".")==FALSE) {
  1260.       /** Cache is still active, spit out the cache file 
  1261.           and get outta here..... **/
  1262.       printfile(sockfd, cachefile, 0, -1);
  1263.       return;
  1264.      }
  1265.  
  1266.      /** If we didn't cache then we have to use a sorting directory... **/
  1267.      SortDir = GDnew(64);
  1268.  
  1269.      /* open "." since we just moved there - makes it work when not
  1270.     chroot()ing and using relative paths */
  1271.      if ((ZeDir = ropendir(".")) == NULL) {
  1272.       Abortoutput(sockfd, "Cannot get that directory");
  1273.       return;
  1274.      }
  1275.  
  1276.      for (dp = readdir(ZeDir); dp != NULL; dp = readdir(ZeDir)) {
  1277.  
  1278.           strcpy(newpath, pathname);
  1279.           if (newpath[strlen(newpath)-1] != '/')
  1280.                strcat(newpath, "/");
  1281.           strcat(newpath, dp->d_name);
  1282.  
  1283.       strcpy(sidename, "./.cap/");
  1284.       strcpy(filename, dp->d_name);
  1285.       strcat(sidename, dp->d_name);
  1286.       
  1287.       if (filename[0] == '.' && 
  1288.           isadir(filename)==0  &&
  1289.           strncmp(filename, ".cache", 6) !=0) {
  1290.            /*** This is a link file, let's process it ***/
  1291.            int linkfd;
  1292.  
  1293.            linkfd = uopen(filename, O_RDONLY);
  1294.  
  1295.            if (linkfd >0) {
  1296.             GDfromLink(SortDir, linkfd, Zehostname, GopherPort);
  1297.             close(linkfd);
  1298.            }
  1299.            
  1300.       }
  1301.  
  1302.       /** Only chew list out files that don't start with a dot **/
  1303.       /** or aren't named dev, usr, bin, etc, or core.         **/
  1304.  
  1305.       if ((filename[0] != '.') && !GDCignore(Config, filename)) {
  1306.            
  1307.            /** Check to see if there's a set-aside file with more info ***/
  1308.            /** But first initialize the Gopherstruct **/
  1309.  
  1310.            GSinit(Gopherp);
  1311.  
  1312.            GSsetHost(Gopherp, Zehostname);
  1313.            GSsetPort(Gopherp, GopherPort);
  1314.            Typep = '\0';
  1315.            Pathp = NULL;
  1316.            
  1317.  
  1318.            Getfiletypes(newpath, filename, &Typep, &Pathp);
  1319.            
  1320.            if (Typep =='3')
  1321.             continue;
  1322.            
  1323.            GSsetType(Gopherp, Typep);
  1324.            GSsetPath(Gopherp, Pathp);
  1325.  
  1326.  
  1327.             if (GSgetTitle(Gopherp) == NULL) {
  1328.             /*** Check to see if we have a compressed file ***/
  1329.             
  1330.             if (strcmp(filename + strlen(filename) -2, ".Z") ==0 &&
  1331.             strcmp(filename + strlen(filename) -6, ".tar.Z") != 0)
  1332.              filename[strlen(filename) - 2] = '\0';
  1333.             
  1334.             GSsetTitle(Gopherp, filename);
  1335.            }
  1336.            else
  1337.             GSsetTitle(Gopherp, filename);
  1338.  
  1339.  
  1340.            if ((SideFile = rfopen(sidename, "r"))!=0) {
  1341.             if (DEBUG == TRUE)
  1342.              printf("Side file name: %s\n", sidename);
  1343.             Process_Side(SideFile, Gopherp);
  1344.            }
  1345.  
  1346. #ifdef DL
  1347.            /* Process a "dl" description if there is one! */
  1348.  
  1349.            dlpath[0] = '.';
  1350.            dlpath[1] = '\0';
  1351.            dlout = getdesc(NULL,dlpath,filename,0);
  1352.  
  1353.            if (DEBUG)
  1354.             printf("dl: %s %s %s\n", dlpath, filename, dlout);
  1355.            if (dlout != NULL) {
  1356.             GSsetTitle(Gopherp, dlout);
  1357.            }
  1358. #endif
  1359.  
  1360.            /*** Add the entry to the directory ***/
  1361.   
  1362.            GDaddGS(SortDir, Gopherp);
  1363.  
  1364.       }
  1365.      }
  1366.      
  1367.      GDsort(SortDir);
  1368.  
  1369.      if (UsingHTML)  {
  1370.       int aboutfd;
  1371.  
  1372.       aboutfd = uopen(".about.html", O_RDONLY);
  1373.       if (aboutfd > 0) {
  1374.            while (readline(aboutfd, newpath, 512))
  1375.             writestring(sockfd, newpath);
  1376.            close(aboutfd);
  1377.       }
  1378.            
  1379.       GDtoNetHTML(SortDir, sockfd);
  1380.      }
  1381.      else {
  1382.       GDtoNet(SortDir, sockfd);
  1383.       writestring(sockfd, ".\r\n");
  1384.      }
  1385.  
  1386.      /*
  1387.       * Write out the cache... *After* we send out the data to the net.
  1388.       */
  1389.      if (Caching) {
  1390.       int cachefd;
  1391.  
  1392.       cachefd = uopen(cachefile, O_WRONLY|O_CREAT|O_TRUNC, 0755);
  1393.  
  1394.       if (cachefd != 0) {
  1395.            if (DEBUG) {
  1396.             printf("Caching directory...\n");
  1397.            }
  1398.            if (UsingHTML) {
  1399.             int aboutfd; 
  1400.  
  1401.             aboutfd = uopen(".about.html", O_RDONLY);
  1402.             if (aboutfd > 0) {
  1403.              while (readline(aboutfd, newpath, 512))
  1404.                   writestring(cachefd, newpath);
  1405.              close(aboutfd);
  1406.             }
  1407.             
  1408.             GDtoNetHTML(SortDir, cachefd);
  1409.            }
  1410.            else
  1411.             GDtoNet(SortDir, cachefd);
  1412.  
  1413.            close(cachefd);
  1414.       }
  1415.      }
  1416.  
  1417.      closedir(ZeDir);
  1418. }
  1419.  
  1420.  
  1421. /*
  1422.  * This processes a file containing any subset of
  1423.  * Type, Name, Path, Port or Host, and returns pointers to the
  1424.  * overriding data that it finds.
  1425.  *
  1426.  * The caller may choose to initialise the pointers - so we don't
  1427.  * touch them unless we find an over-ride.
  1428.  */
  1429.  
  1430. void
  1431. Process_Side(sidefile, Gopherp)
  1432.   FILE *sidefile;
  1433.   GopherObj *Gopherp;
  1434. {
  1435.      char inputline[MAXLINE];
  1436.      char *cp;
  1437.  
  1438.  
  1439.      inputline[0] = '\0';
  1440.  
  1441.      for (;;) {
  1442.       for (;;) {
  1443.            cp = fgets(inputline, 1024, sidefile);
  1444.            if (inputline[0] != '#' || cp == NULL)
  1445.             break;
  1446.       }
  1447.       
  1448.       /*** Test for EOF ***/
  1449.       if (cp==NULL)
  1450.            break;
  1451.       
  1452.       ZapCRLF(inputline);  /* should zap tabs as well! */
  1453.  
  1454.       /*** Test for the various field values. **/
  1455.       
  1456.       if (strncmp(inputline, "Type=", 5)==0) {
  1457.            GSsetType(Gopherp, inputline[5]);
  1458.            if (inputline[5] == '7') {
  1459.             /*** Might as well set the path too... ***/
  1460.             *(GSgetPath(Gopherp)) = '7';
  1461.            }
  1462.            if (inputline[5] == '9') {
  1463.             /*** Might as well set the path too... ***/
  1464.             *(GSgetPath(Gopherp)) = '9';
  1465.            }
  1466.       }
  1467.  
  1468.       else if (strncmp(inputline, "Name=", 5)==0) {
  1469.            GSsetTitle(Gopherp, inputline+5);
  1470.       }
  1471.  
  1472.       else if (strncmp(inputline, "Host=", 5)==0) {
  1473.            GSsetHost(Gopherp, inputline+5);
  1474.       }
  1475.  
  1476.       else if (strncmp(inputline, "Port=", 5)==0) {
  1477.            GSsetPort(Gopherp, atoi(inputline+5));
  1478.       }
  1479.  
  1480.       else if (strncmp(inputline, "Path=", 5)==0) {
  1481.            GSsetPath(Gopherp, inputline+5);
  1482.       }
  1483.  
  1484.       else if (strncmp(inputline, "Numb=", 5)==0) {
  1485.            GSsetNum(Gopherp, atoi(inputline+5));
  1486.       }
  1487.  
  1488.       else if (strncmp(inputline, "Name=", 5)==0) {
  1489.            GSsetTitle(Gopherp, inputline+5);
  1490.       }
  1491.  
  1492.      }
  1493.  
  1494.      fclose(sidefile);
  1495. }
  1496.  
  1497.  
  1498.  
  1499.  
  1500.  
  1501. /*
  1502. ** This function opens the specified file, starts a zcat if needed,
  1503. ** and barfs the file across the socket.
  1504. **
  1505. ** It now also checks and sees if access is allowed
  1506. **
  1507. **
  1508. */
  1509.  
  1510. void
  1511. printfile(sockfd, pathname, startbyte, endbyte)
  1512.   int sockfd;
  1513.   char *pathname;
  1514.   int startbyte, endbyte;
  1515. {
  1516.      FILE *ZeFile;
  1517.      char inputline[512];
  1518.  
  1519.  
  1520.      /*** Check and see if the peer has permissions to read files ***/
  1521.      
  1522.      if (Can_Read(sockfd) == FALSE) {
  1523.       char tmpstr[256];
  1524.       if (writestring(sockfd, GDCgetBummerMsg(Config)) <0)
  1525.            LOGGopher(sockfd, "Client went away"), exit(-1);
  1526.       writestring(sockfd, "\r\nBummer.....\r\n.\r\n");
  1527.       sprintf(tmpstr, "Denied access for %s", pathname);
  1528.       LOGGopher(sockfd, tmpstr);
  1529.       return;
  1530.      }
  1531.  
  1532.      if (UsingHTML && strcmp(pathname, ".cache.html") != 0) {
  1533.       writestring(sockfd, "<XMP>\r\n");
  1534.      }
  1535.  
  1536.  
  1537.      if ( (ZeFile = rfopen(pathname, "r")) == NULL) {
  1538.       /*
  1539.        * The specified file does not exist
  1540.        */
  1541.       char notexistline[256];
  1542.       sprintf(notexistline, "'%s' does not exist!!", pathname);
  1543.       Abortoutput(sockfd, notexistline);
  1544.  
  1545.       return;
  1546.      }
  1547.  
  1548.      if (startbyte != 0)
  1549.       fseek(ZeFile, startbyte, 0);
  1550.  
  1551.      {
  1552.       FILE *pp;
  1553.       if (pp = specialfile(ZeFile, pathname)) {
  1554.            fclose(ZeFile);
  1555.            ZeFile = pp;
  1556.       }
  1557.      }
  1558.  
  1559.  
  1560.      while (fgets(inputline, MAXLINE, ZeFile) != NULL) {
  1561.  
  1562.       ZapCRLF(inputline);
  1563.  
  1564.       /** Period on a line by itself, double it.. **/
  1565.       if (*inputline == '.' && inputline[1] == '\0') {
  1566.            inputline[1] = '.';
  1567.            inputline[2] = '\0';
  1568.       }
  1569.  
  1570.       strcat(inputline, "\r\n");
  1571.       if (writestring(sockfd, inputline) <0)
  1572.            LOGGopher(sockfd, "Client went away"), exit(-1);
  1573.  
  1574.       if (endbyte >0) {
  1575.            if (ftell(ZeFile) >= endbyte)
  1576.             break;
  1577.       }
  1578.      }
  1579.  
  1580.      Specialclose(ZeFile);
  1581.  
  1582.      if (UsingHTML) {
  1583.       writestring(sockfd, "</XMP>\r\n");
  1584.      }
  1585.  
  1586.      if (writestring(sockfd, ".\r\n")<0)
  1587.       LOGGopher(sockfd, "Client went away"), exit(-1);
  1588. }
  1589.  
  1590.  
  1591. #define BUFSIZE 1523  /* A pretty good value for ethernet */
  1592.  
  1593. void
  1594. echosound(sockfd, filename)
  1595.   int sockfd;
  1596.   char *filename;
  1597. {
  1598.  
  1599.      FILE *sndfile;
  1600.      unsigned char in[BUFSIZE];
  1601.      register int j;
  1602.      int gotbytes;
  1603.  
  1604.      if (Can_Read(sockfd) == FALSE) {
  1605.       char tmpstr[256];
  1606.       if (writestring(sockfd, GDCgetBummerMsg(Config)) <0)
  1607.            LOGGopher(sockfd, "Client went away"), exit(-1);
  1608.       writestring(sockfd, "\r\nBummer.....\r\n.\r\n");
  1609.       sprintf(tmpstr, "Denied access for %s", filename);
  1610.       LOGGopher(sockfd, tmpstr);
  1611.       return;
  1612.      }
  1613.  
  1614.      if (strcmp(filename, "-") == 0) {
  1615.       /*** Do some live digitization!! **/
  1616.       sndfile = popen("record -", "r");
  1617.      }
  1618.      else
  1619.       sndfile = rfopen(filename, "r");
  1620.  
  1621.      while(1) {
  1622.       gotbytes = fread(in, 1, BUFSIZE, sndfile);
  1623.       
  1624.       if (gotbytes == 0)
  1625.            break;       /*** end of file or error... ***/
  1626.  
  1627.           j = writen(sockfd, in, gotbytes);
  1628.  
  1629.       if (j == 0)
  1630.            break;       /*** yep another error condition ***/
  1631.  
  1632.      }
  1633. }
  1634.  
  1635.